#include "LibraryInterface.h"

BITMAP* LibraryInterface::buffer;
std::map <unsigned int, Sprite> LibraryInterface::spriteMap;


//a new set of timing variables to keep the game time
volatile int LibraryInterface::frameTicks;
volatile int LibraryInterface::totalTicks;
unsigned int LibraryInterface::FPS;
unsigned int LibraryInterface::previousTotalTicks;
unsigned int LibraryInterface::frameCount;

APPLICATION_STATE LibraryInterface::applicationState;

LibraryInterface::LibraryInterface(){}
LibraryInterface::~LibraryInterface(){

	destroy_bitmap(buffer);
	allegro_exit();
}

bool LibraryInterface::Initialize(){
	srand(time(NULL));

	allegro_init();
	set_gfx_mode(GFX_SAFE, 640, 480, 0, 0);
	install_keyboard();
	install_mouse();


	//init the double buffer
	buffer = create_bitmap (WIDTH, HEIGHT);
	clear_bitmap(buffer);

	//timing
	install_timer();

	frameTicks = 0;
	totalTicks = 0;
	FPS = 0;
	previousTotalTicks = 0;
	frameCount = 0;

	//initialize the timer
	LOCK_VARIABLE(LibraryInterface::Ticks);
	LOCK_FUNCTION(LibraryInterface::IncrementFrameTicks);
	install_int_ex(LibraryInterface::IncrementFrameTicks, BPS_TO_TIMER(FRAMES_PER_SECOND));

	LOCK_VARIABLE(LibraryInterface::totalTicks);
	LOCK_FUNCTION(LibraryInterface::IncrementTotalTicks);
	install_int_ex(LibraryInterface::IncrementTotalTicks, BPS_TO_TIMER(10));//i.e. game time is in tenths of seconds

	//allow use of x button to close window
    LOCK_FUNCTION(TerminateApplication);
    set_close_button_callback(LibraryInterface::TerminateApplication);  
	applicationState = RUN;

	//change window title
    set_window_title("Dalton");

	show_mouse(screen);

	

	return true;
}
bool LibraryInterface::LoadSprite(unsigned int sprite_number){
	Sprite sprite = Sprite();
	bool success = sprite.Initialize(sprite_number);
	if(!success) return false;
	spriteMap[sprite_number] = sprite;
	return true;
}
bool LibraryInterface::Update(){
	return true;
}
bool LibraryInterface::Blit(Sprite* s){
   //blit a portion of the sheet to the frame
    blit(s->GetImage(), buffer, 0, 0, s->GetX(), s->GetY(), s->GetW(), s->GetH());
    return true;
}
bool LibraryInterface::Blit(SpriteAnimation* a){
    blit(a->GetCurrentFrame(), buffer, 0, 0, a->GetX(), a->GetY(), a->GetW(), a->GetH());
    //make a post-on-frame-callback for this later
    a->Update();
    return true;
}
bool LibraryInterface::Render(){
	vsync();
	
	//blit the double buffer
	acquire_screen();	
	stretch_blit(buffer, screen, 0, 0, WIDTH, HEIGHT,0,0, SCREEN_WIDTH, SCREEN_HEIGHT);
	release_screen();

	clear_bitmap(buffer);
	return true;
}
bool LibraryInterface::Deinitialize(){
	//Deinitialize() all sprites in spriteMap
	//to clear the image data
	std::map<unsigned int, Sprite>::iterator p;
	for(p = spriteMap.begin(); p != spriteMap.end(); p++)
		spriteMap[p->first].Deinitialize();
	
	//clear the spriteMap of elements
	spriteMap.clear();
	
	allegro_exit();
	return true;
}
void LibraryInterface::Print(char* output, int x, int y){
	textout_ex(	buffer, 
				font, 
				output, 
				x,
				y,
				WHITE, 
				-1);
	
}
void LibraryInterface::Print(int output, int x, int y){
	textprintf(buffer, font, x, y, WHITE, "%d", output);	
}
void LibraryInterface::Print(float output, int x, int y){
	textprintf(buffer, font, x, y, WHITE, "%f", output);	
}
void LibraryInterface::Print(std::string output, int x, int y){
	const char* c_string = output.c_str();
	textprintf(buffer, font, x, y, WHITE, c_string);
}
void LibraryInterface::IncrementFrameTicks(){
	frameTicks++;
}END_OF_FUNCTION(IncrementFrameTicks)
void LibraryInterface::IncrementTotalTicks(){
	totalTicks++;
}END_OF_FUNCTION(IncrementTotalTicks)

void LibraryInterface::Spin(unsigned int waiting_time){
	rest(waiting_time);

}
unsigned int LibraryInterface::GetFPS(){
	return FPS;
}
void LibraryInterface::PreOnFrameUpdate(){
	while(frameTicks == 0){
		//rest until a full tick has passed
		Spin(1);
	}

	Timer::UpdateAllTimers();
}
unsigned int LibraryInterface::PostOnFrameUpdate(){

	//flip the back-buffer
	Render();

	if(totalTicks - previousTotalTicks >= 10)//i.e. a second has passed since we last measured the frame rate
	{
		FPS = frameCount;
		//fps now holds the the number of frames done in the last second
		//you can now output it using textout_ex et al.

		//reset for the next second
		frameCount = 0;
		previousTotalTicks = totalTicks;
	}
	frameCount++;//we drew a frame!
	frameTicks--;
	
	return FPS;
}
void LibraryInterface::PrintDebugInfo(){
	int font_size = GetFontSize();
	int x = WIDTH;
	int y = -font_size;
	
	textprintf_right_ex(buffer, font, x, y+=font_size, WHITE, BLUE, "FPS: %d", FPS);
    /*textprintf_right_ex(buffer, font, x, y+=font_size, WHITE, BLUE, "Entities: %d", Entity::GetEntityCount());*/
	
	
	
}
unsigned int LibraryInterface::GetFontSize(){
	return font->height;
}
void LibraryInterface::DrawRect(unsigned int x, unsigned int y, unsigned int half_of_width, unsigned int half_of_height, int r, int g, int b){
    int red = abs(r)%256;
	int green = abs(g)%256;
	int blue = abs(b)%256;
	rect(buffer, x-half_of_width, y-half_of_height, x+half_of_width, y+half_of_height, makecol(red, green, blue));
}
void LibraryInterface::DrawFilledRect(unsigned int x, unsigned int y, unsigned int half_of_width, unsigned int half_of_height, int r, int g, int b){
	int red = abs(r)%256;
	int green = abs(g)%256;
	int blue = abs(b)%256;
	rectfill(buffer, 
		x-half_of_width, 
		y-half_of_height, 
		x+half_of_width, 
		y+half_of_height, 
		makecol(red, green, blue));
}
void LibraryInterface::DrawCircle(unsigned int x, unsigned int y, unsigned int radius, int r, int g, int b){
    int red = abs(r)%256;
    int green = abs(g)%256;
    int blue = abs(b)%256;
    circle(buffer, x, y, radius, makecol(red, green, blue));
}
void LibraryInterface::DrawFilledCircle(unsigned int x, unsigned int y, unsigned int radius, int r, int g, int b){
    int red = abs(r)%256;
    int green = abs(g)%256;
    int blue = abs(b)%256;
    circlefill(buffer, x, y, radius, makecol(red, green, blue));
}
void LibraryInterface::TerminateApplication(void){
   applicationState = QUIT;
}
END_OF_FUNCTION(TerminateApplication)
APPLICATION_STATE LibraryInterface::GetApplicationState(){
	return applicationState;
}
void LibraryInterface::SetApplicationState(APPLICATION_STATE application_state){
	applicationState = application_state;
}
